package org.moonlight.jvm.utils;

import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 方法描述符解析工具类
 *
 * @author Moonlight
 * @createTime 2023/9/12 11:18
 **/
@Getter
public class MethodDescriptor {

    private final List<String> parameterTypes;
    private String returnType;

    private MethodDescriptor() {
        this.parameterTypes = new ArrayList<>();
    }

    public static MethodDescriptor methodDescriptor(String methodDescriptor) {
        return new MethodDescriptorParse(methodDescriptor).parse();
    }

    private static class MethodDescriptorParse {
        /**
         * 原始的方法描述符
         **/
        private String rawDescriptor;
        /**
         * 解析偏移量
         **/
        private int offset;
        /**
         * 解析结果
         **/
        private MethodDescriptor parsed;

        private MethodDescriptorParse(String rawDescriptor) {
            this.rawDescriptor = rawDescriptor;
            this.parsed = new MethodDescriptor();
        }

        private MethodDescriptor parse() {
            this.paramsStart();
            this.paramsTypeParse();
            this.paramsEnd();
            this.returnTypeParse();
            this.finish();
            return this.parsed;
        }
        /**
         * 开始解析方法描述符的参数部分，方法描述符的参数部分必须以 ( 开头
         * @createTime 11:39 2023/9/12
         * @author moonlight
         **/
        private void paramsStart() {
            if (this.readChar() != '(') {
                this.throwException();
            }
        }

        /**
         * 解析方法描述符的参数部分
         * @createTime 11:45 2023/9/12
         * @author moonlight
         **/
        private void paramsTypeParse() {
            while (true) {
               String type = this.parseFieldType();
               if (StringUtils.isNotBlank(type)) {
                   this.parsed.parameterTypes.add(type);
               } else {
                   break;
               }
            }
        }

        /**
         * 解析方法描述符的返回值部分
         * @createTime 11:47 2023/9/12
         * @author moonlight
         **/
        private void returnTypeParse() {
            // 先往前看一下，是不是 V, 如果是 V 说明返回值是 void
            if (this.readChar() == 'V') {
                this.parsed.returnType = "V";
                return;
            }
            // 如果返回值不是 void 那么就需要后退一步，因为前面已经往前看了一眼
            this.unreadChar();

            String returnType = this.parseFieldType();
            if (StringUtils.isNotBlank(returnType)) {
                this.parsed.returnType = returnType;
                return;
            }

            this.throwException();
        }

        /**
         * 解析 参数 或者 返回值 的 字段类型
         * @return String
         * @createTime 11:52 2023/9/12
         * @author moonlight
         **/
        private String parseFieldType() {
            switch (this.readChar()) {
                case 'B':
                    return "B";
                case 'C':
                    return "C";
                case 'D':
                    return "D";
                case 'F':
                    return "F";
                case 'I':
                    return "I";
                case 'J':
                    return "J";
                case 'S':
                    return "S";
                case 'Z':
                    return "Z";
                case 'L':
                    return this.parseObjectType();
                case '[':
                    return this.parseArrayType();
                default:
                    this.unreadChar();
                    return "";
            }
        }

        /**
         * 解析 对象 返回值
         * @return String 返回值的类名
         * @createTime 11:54 2023/9/12
         * @author moonlight
         **/
        private String parseObjectType() {
            String substring = this.rawDescriptor.substring(this.offset);
            int semicolonIdx = substring.indexOf(';');
            if (semicolonIdx == -1) {
                this.throwException();
                return "";
            }
            int objStart = this.offset - 1;
            int objEnd = this.offset + semicolonIdx + 1;
            this.offset = objEnd;
            return this.rawDescriptor.substring(objStart, objEnd);
        }

        /**
         * 解析 数组 返回值
         * @return String 数组的类名
         * @createTime 11:55 2023/9/12
         * @author moonlight
         **/
        private String parseArrayType() {
            int arrStart = this.offset - 1;
            this.parseFieldType();
            int arrEnd = this.offset;
            return this.rawDescriptor.substring(arrStart, arrEnd);
        }

        /**
         * 方法描述符的参数部分解析结束，方法描述符的参数部分必须以 ) 结尾
         * @createTime 11:39 2023/9/12
         * @author moonlight
         **/
        private void paramsEnd() {
            if (this.readChar() != ')') {
                this.throwException();
            }
        }

        /**
         * 整个方法描述符解析结束时，解析偏移量必须在 方法描述符 的末尾处
         * @createTime 11:44 2023/9/12
         * @author moonlight
         **/
        private void finish() {
            if (this.offset != this.rawDescriptor.length()) {
                this.throwException();
            }
        }

        /**
         * 从方法描述符中读取一个字节的char数据, 并将 解析偏移量往前推一步
         * @return char
         * @createTime 11:41 2023/9/12
         * @author moonlight
         **/
        private char readChar() {
            return this.rawDescriptor.charAt(this.offset++);
        }

        /**
         * 解析偏移量后退一步
         * @createTime 11:41 2023/9/12
         * @author moonlight
         **/
        private void unreadChar() {
            this.offset--;
        }

        private void throwException() {
            throw new RuntimeException("Bad descriptor: " + this.rawDescriptor);
        }
    }

}